#include "swpitemcommands.h"

#include "../editors/items/abstractpolygongraphicitem.h"
#include "../editors/items/abstractrectgraphicitem.h"
#include "../editors/items/swpswimlanegraphicitem.h"

#include <igraphicitemcontent.h>

using namespace core;
using namespace swp;

PolygonGraphicItemResizeCommand::PolygonGraphicItemResizeCommand(
    AbstractPolygonGraphicItem* item,
    qreal xCoefficient, qreal yCoefficient, bool ignoreFirstRedo) :
        QUndoCommand(),
        m_item(item),
        m_xCoefficient(xCoefficient),
        m_yCoefficient(yCoefficient),
        m_ignoreFirstRedo(ignoreFirstRedo)
{
    setText(QObject::tr("%1 item resized").arg(item->name()));
}

PolygonGraphicItemResizeCommand::~PolygonGraphicItemResizeCommand()
{

}

void PolygonGraphicItemResizeCommand::undo()
{
    QTransform transform;
    transform.scale(m_xCoefficient, m_yCoefficient);
    transform = transform.inverted();
    QPolygonF transformed = transform.map(m_item->m_polygon);

    if (m_item->m_connectPoints.empty())
    {
        m_item->m_connectPoints = m_item->connectPoints();
    }

    QPolygonF connectPointsTransformed = transform.map(
        QPolygonF(m_item->m_connectPoints.toVector()));
    m_item->m_connectPoints = connectPointsTransformed.toList();

    m_item->setPolygonF(transformed);

    m_item->refreshAuxiliaryLayers();
    m_item->updateConnectionPositions();

    if (m_item->m_content != 0)
    {
        m_item->m_content->recheckIfFits();
    }
}

void PolygonGraphicItemResizeCommand::redo()
{
    if (!m_ignoreFirstRedo)
    {
        QTransform transform;
        transform.scale(m_xCoefficient, m_yCoefficient);
        QPolygonF transformed = transform.map(m_item->m_polygon);

        if (m_item->m_connectPoints.empty())
        {
            m_item->m_connectPoints = m_item->connectPoints();
        }

        QPolygonF connectPointsTransformed = transform.map(
            QPolygonF(m_item->m_connectPoints.toVector()));
        m_item->m_connectPoints = connectPointsTransformed.toList();

        m_item->setPolygonF(transformed);

        m_item->refreshAuxiliaryLayers();
        m_item->updateConnectionPositions();

        if (m_item->m_content != 0)
        {
            m_item->m_content->recheckIfFits();
        }
    }

    m_ignoreFirstRedo = false;
}

RectGraphicItemResizeCommand::RectGraphicItemResizeCommand(
    AbstractRectGraphicItem* item,
    qreal xCoefficient, qreal yCoefficient, bool ignoreFirstRedo) :
        QUndoCommand(),
        m_item(item),
        m_xCoefficient(xCoefficient),
        m_yCoefficient(yCoefficient),
        m_ignoreFirstRedo(ignoreFirstRedo)
{
    setText(QObject::tr("%1 item resized").arg(item->name()));
}

RectGraphicItemResizeCommand::~RectGraphicItemResizeCommand()
{

}

void RectGraphicItemResizeCommand::undo()
{
    QTransform transform;
    transform.scale(m_xCoefficient, m_yCoefficient);
    transform = transform.inverted();
    QRectF transformed = transform.mapRect(m_item->m_rect);

    if (m_item->m_connectPoints.empty())
    {
        m_item->m_connectPoints = m_item->connectPoints();
    }

    QPolygonF connectPointsTransformed = transform.map(
        QPolygonF(m_item->m_connectPoints.toVector()));
    m_item->m_connectPoints = connectPointsTransformed.toList();

    m_item->setRectF(transformed);

    m_item->refreshAuxiliaryLayers();
    m_item->updateConnectionPositions();

    if (m_item->m_content != 0)
    {
        m_item->m_content->recheckIfFits();
    }
}

void RectGraphicItemResizeCommand::redo()
{
    if (!m_ignoreFirstRedo)
    {
        QTransform transform;
        transform.scale(m_xCoefficient, m_yCoefficient);
        QRectF transformed = transform.mapRect(m_item->m_rect);

        if (m_item->m_connectPoints.empty())
        {
            m_item->m_connectPoints = m_item->connectPoints();
        }

        QPolygonF connectPointsTransformed = transform.map(
            QPolygonF(m_item->m_connectPoints.toVector()));
        m_item->m_connectPoints = connectPointsTransformed.toList();

        m_item->setRectF(transformed);

        m_item->refreshAuxiliaryLayers();
        m_item->updateConnectionPositions();

        if (m_item->m_content != 0)
        {
            m_item->m_content->recheckIfFits();
        }
    }

    m_ignoreFirstRedo = false;
}

SwapSwimlanesCommand::SwapSwimlanesCommand(SwpSwimlaneGraphicItem* first,
    SwpSwimlaneGraphicItem* second) : QUndoCommand(),
        m_first(first),
        m_second(second)
{
    setText(QObject::tr("Swimlanes has been swapped"));
}

SwapSwimlanesCommand::~SwapSwimlanesCommand()
{

}

void SwapSwimlanesCommand::undo()
{
    if (m_second->previous() != 0)
    {
        m_second->previous()->setNext(m_first);
    }

    if (m_first->next() != 0)
    {
        m_first->next()->setPrevious(m_second);
    }

    m_first->setPrevious(m_second->previous());
    m_second->setNext(m_first->next());

    m_first->setNext(m_second);
    m_second->setPrevious(m_first);

    m_first->setIgnoreFlag(true);
    m_second->setIgnoreFlag(true);

    m_first->setPos(m_second->pos());
    m_second->setPos(m_first->pos().x() +
        m_first->boundingRectWithoutHandles().width(), 0);

    m_first->setIgnoreFlag(false);
    m_second->setIgnoreFlag(false);

    m_second->stackBefore(m_first);
}

void SwapSwimlanesCommand::redo()
{
    if (m_first->previous() != 0)
    {
        m_first->previous()->setNext(m_second);
    }

    if (m_second->next() != 0)
    {
        m_second->next()->setPrevious(m_first);
    }

    m_second->setPrevious(m_first->previous());
    m_first->setNext(m_second->next());

    m_second->setNext(m_first);
    m_first->setPrevious(m_second);

    m_first->setIgnoreFlag(true);
    m_second->setIgnoreFlag(true);

    m_second->setPos(m_first->pos());
    m_first->setPos(m_second->pos().x() +
        m_second->boundingRectWithoutHandles().width(), 0);

    m_first->setIgnoreFlag(false);
    m_second->setIgnoreFlag(false);

    m_first->stackBefore(m_second);
}
